/**
 * 贪吃蛇 https://www.bilibili.com/video/BV1vs411n7TH/?p=129
 * 1.通过键盘控制方向(wsad 或 ↑↓←→), '空格'暂停.
 * 2.生成食物, 每吃1口就得到一定的积分, 而且蛇的身子会越来越长.
 * 3.不能撞墙, 不能咬到自己的身体, 也不能咬到自己的尾巴.
 * 4.按空格暂停, 显示分数.
 * 5.直到一定的分数, 就算过关.
 * 6.然后下一关.
 *
 * 注意: 不要在CLion自带控制台运行, 不然效果不好.
 */
#include <stdio.h>
#include <conio.h>
#include <synchapi.h>
#include "gluttonous_snake.h"
#include "../Utils/Random.h"

int main() {
    //1.画墙&文字说明
    draw_wall_text();
    /**
     * 2.定义一条蛇, 原始长度=8
     */
    snake.size = 8;
    initSnake();
    //3.画食物
    drawFood();
    //4.画蛇
    drawSnake(NULL);
    //开始监听&玩游戏
    playGame();
    return 0;
}

//1.画墙&文字说明
static void draw_wall_text() {
    //画墙
    for (SHORT i = 0; i < height; ++i) {
        setConsoleCursorPosition(width, i);
//        putchar('x');
        printf("▓");
    }
    for (SHORT j = 0; j <= width; ++j) {
        setConsoleCursorPosition(j, height);
//        putchar('=');
        printf("━");
    }
    //画文字
    setConsoleCursorPosition(0, height + 1);
    printf("贪吃蛇说明:\n"
           "    1.(wsad 或 ↑↓←→)控制方向, '空格'暂停/继续, '+'和'-'控制速度.\n"
           "    2.不能撞墙, 不能咬到自己的身体, 也不能咬到自己的尾巴.\n"
           "\n"
           "当前分数: %d\n"
           "当前速度: %6.4f\n", score, (float) 1000 / stepTime);
    //隐藏光标
    setConsoleCursorInfo(FALSE);
}

//2.初始化蛇
static void initSnake() {
    snake.bodys[0].X = width / 2;
    snake.bodys[0].Y = height / 2;
    for (int i = 1; i < snake.size; ++i) {
        snake.bodys[i].X = width / 2;
        snake.bodys[i].Y = snake.bodys[i - 1].Y + 1;
    }
}
//3.画食物(不要和蛇重叠)
static void drawFood() {
    SHORT x, y;
    do {
        x = getRandom() % width;
        y = getRandom() % height;
    } while (is_overlap_snake(x, y));
    food[0] = x;
    food[1] = y;
    setConsoleCursorPosition(x, y);
    putchar('o');
}

//4.画蛇
static void drawSnake(COORD *tail) {
    if (tail != NULL) {
        //去掉尾巴
        setConsoleCursorPosition(tail->X, tail->Y);
        putch(' ');
    }
    for (int i = 0; i < snake.size; ++i) {
        //光标移动到蛇的身子部位
        setConsoleCursorPosition(snake.bodys[i].X, snake.bodys[i].Y);
        if (i == 0) {
            printf("H");
        } else putch('*');
    }
}
//5.开始游戏
static void playGame() {
    while (!isGameOver) {
        struct Keyboard_Key key = getKeyInput(0);
        deal_pressed_key(key);
        //如果是暂停
        if (isPause) continue;
        //1.根据方向, 蛇走1步, 计算蛇头坐标
//        COORD head = snake.bodys[0];
        COORD tail = snake.bodys[snake.size - 1];
        for (int i = snake.size - 1; i > 0; --i) {
            snake.bodys[i].X = snake.bodys[i - 1].X;
            snake.bodys[i].Y = snake.bodys[i - 1].Y;
        }
        switch (oritation) {
            case 'w': snake.bodys[0].Y--; break;  //不能使用head.Y++ 赋值的方式
            case 's': snake.bodys[0].Y++;break;
            case 'a': snake.bodys[0].X--;break;
            case 'd': snake.bodys[0].X++;break;
            default: break;
        }
        //2.判断是否撞墙 or 是否撞到自己身体
        if (is_bump_wall_or_self()) {
            isGameOver = TRUE;
        } else {
            //3.判断是否吃到食物, if吃到就增加长度&分数, 重新生成食物
            BOOLEAN hasEat = judge_eat_food(tail.X, tail.Y);
            if (hasEat) drawFood();
        }
        drawSnake(&tail);
        //4.直到一定的分数就过关
        Sleep(stepTime);
    }
    setConsoleCursorPosition(width / 2 - 13, height / 2);
    printf("游戏结束啦, 按任意键退出!!");
    getch();
}

static void deal_pressed_key(struct Keyboard_Key pKey) {
    if (pKey.isPressed == FALSE) return;
    enum KeyBoard_Type keyBoard = pKey.keyBoardType;
    int ch = pKey.ch;
//    printf("=%d\n", ch);
    if (keyBoard == Ascii) {
        //转小写
        if (ch >= 'A' && ch <= 'Z') {
            ch = ch - 'A';
        } else if (ch >= 'a' && ch <= 'z') {
            //本来就是小写字母
        } else if (ch == ' ') {
            //暂停
            isPause = TRUE - isPause;
            return;
        } else if (ch == '+' || ch == '-') {
            //增加/减少速度
            if (ch == '+' && stepTime > 50) {
                stepTime -= 50;
            } else if (ch == '-' && stepTime < 1000) {
                stepTime += 50;
            } else return;
            setConsoleCursorPosition(0, height + 6);
            printf("当前速度: %6.4f\n", (float) 1000 / stepTime);
            return;
        } else {
            //其它 ASCII 字符
            return;
        }
    } else if (keyBoard == Arrow) {
        //箭头: ↑72, ←75, →77, ↓80
        if (ch == 72) {
            ch = 'w';
        } else if (ch == 75) {
            ch = 'a';
        } else if (ch == 77) {
            ch = 'd';
        } else if (ch == 80) {
            ch = 's';
        } else {
            printf("接收到了什么奇怪方向? (%c)=%d\n", ch, ch);
            return;
        }
    } else {
        //如果是其它类型的按键
        return;
    }
    //方向相同
    if (oritation == ch) return;
    //方向完全相反
    if (oritation == 'w' && ch == 's') return;
    if (oritation == 's' && ch == 'w') return;
    if (oritation == 'a' && ch == 'd') return;
    if (oritation == 'd' && ch == 'a') return;
    oritation = ch;
}